// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
// This source file is part of the Cangjie project, licensed under Apache-2.0
// with Runtime Library Exception.
//
// See https://cangjie-lang.cn/pages/LICENSE for license information.

#include "cangjie/AST/Match.h"

#include "NodeCast.h"
#include "Rules/Rule.h"

#include "Rules/TypeNameMatchRule.h"

namespace CangjieMigrator::Rules {

TypeNameMatchRule::TypeNameMatchRule(std::string package, std::string typeName)
    : package(std::move(package)), typeName(std::move(typeName))
{}

MatchRule::Type TypeNameMatchRule::GetType() const
{
    return Type::TypeName;
}

template<typename T>
static std::unique_ptr<ExtractedInfo> ExtractInfoImpl(const T &node, const PositionRange &range)
{
    static_assert(std::is_same_v<T, Cangjie::AST::RefExpr> || std::is_same_v<T, Cangjie::AST::RefType>,
        "Only RefExpr and RefType are supported");

    const auto &ref = node.ref;
    const auto &target = ref.target;
    if (!target) {
        return nullptr;
    }

    auto package = target->fullPackageName;
    if (package == "default") { // Local Variable
        return nullptr;
    }

    auto identifier = ref.identifier.GetRawText();

    if (node.leftAnglePos.IsZero()) {
        return std::make_unique<TypeNameExtractedInfo>(range, node, package, identifier);
    }

    const auto leftAnglePos = node.GetMacroCallPos(node.leftAnglePos);
    if (leftAnglePos.fileID != range.start.fileID) {
        return nullptr;
    }

    return std::make_unique<TypeNameExtractedInfo>(PositionRange(range.start, leftAnglePos), node, package, identifier);
}

std::unique_ptr<ExtractedInfo> TypeNameMatchRule::ExtractInfo(
    const Cangjie::AST::Node &node, const PositionRange &range)
{
    if (node.astKind == Cangjie::AST::ASTKind::REF_TYPE) {
        return ExtractInfoImpl<Cangjie::AST::RefType>(Cast<Cangjie::AST::ASTKind::REF_TYPE>(node), range);
    }
    if (node.astKind == Cangjie::AST::ASTKind::REF_EXPR) {
        return ExtractInfoImpl<Cangjie::AST::RefExpr>(Cast<Cangjie::AST::ASTKind::REF_EXPR>(node), range);
    }
    return nullptr;
}

bool TypeNameMatchRule::MatchConditions(const ExtractedInfo *info)
{
    const auto typeNameInfo = dynamic_cast<const TypeNameExtractedInfo *>(info);
    if (!typeNameInfo) {
        return false;
    }

    if (typeNameInfo->package != package || typeNameInfo->typeName != typeName) {
        return false;
    }

    return true;
}

std::vector<Actions::Action> TypeNameMatchRule::GenerateAction(
    UpdateInstance::File &file, const ExtractedInfo &info, const std::string &update, const Rule *rule) const
{
    if (update.empty()) {
        return {};
    }
    const auto i = dynamic_cast<const TypeNameExtractedInfo &>(info);
    return {Actions::Replace(i.replacePosition, update, rule)};
}

std::unique_ptr<MatchRule> TypeNameMatchRule::TryBuild(const TomlConfig &config)
{
    if (config.title != "TypeName") {
        return nullptr;
    }
    GET_VALUE_IF_EMPTY_RETURN_NULL(config, package);
    GET_VALUE_IF_EMPTY_RETURN_NULL(config, typeName);
    return std::make_unique<TypeNameMatchRule>(package, typeName);
}

} // namespace CangjieMigrator::Rules
